package com.dragon.quartz.utils;

import com.dragon.common.utils.StringUtils;
import com.dragon.quartz.constant.QuartzConstant;
import com.dragon.quartz.domain.QuartzJob;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Quartz工具类
 *
 * @author dragon
 * @version 1.0
 * @date 2024/9/6 14:36
 */
public class QuartzUtils {

    private static final Logger log = LoggerFactory.getLogger(QuartzUtils.class);

    /**
     * 得到quartz任务类
     *
     * @param job 执行计划
     * @return 具体执行任务类
     */
    private static Class<? extends Job> getQuartzJobClass(QuartzJob job) {

        if (StringUtils.isBlank(job.getJobClass())) {
            boolean isConcurrent = job.getConcurrent() == 0;
            return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class;
        } else {
            try {
                return (Class<? extends Job>) Class.forName(job.getJobClass());
            } catch (ClassNotFoundException e) {
                throw new RuntimeException("任务执行类不存在");
            }
        }
    }

    /**
     * 构建任务触发对象
     */
    public static TriggerKey getTriggerKey(String jobName, String jobGroup) {
        if (StringUtils.isBlank(jobGroup)) {
            return TriggerKey.triggerKey(jobName);
        }

        return TriggerKey.triggerKey(jobName, jobGroup);
    }

    /**
     * 构建任务键对象
     */
    public static JobKey getJobKey(String jobName, String jobGroup) {
        if (StringUtils.isBlank(jobGroup)) {
            return JobKey.jobKey(jobName);
        }

        return JobKey.jobKey(jobName, jobGroup);
    }

    /**
     * 创建定时任务
     *
     * @param scheduler 调度者
     * @param job       执行计划
     */
    public static void createScheduleJob(Scheduler scheduler, QuartzJob job) {
        try {
            Class<? extends Job> jobClass = getQuartzJobClass(job);
            // 构建job信息
            String jobName = job.getJobName();
            String jobGroup = job.getJobGroup();
            JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobName, jobGroup)).build();

            // 表达式调度构建器
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
            cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder);

            // 按新的cronExpression表达式构建一个新的trigger
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobName, jobGroup))
                .withSchedule(cronScheduleBuilder).build();

            // 放入参数，运行时的方法可以获取
            jobDetail.getJobDataMap().put(QuartzConstant.TASK_PROPERTIES, job);

            // 判断是否存在
            if (scheduler.checkExists(getJobKey(jobName, jobGroup))) {
                // 防止创建时存在数据问题 先移除，然后在执行创建操作
                scheduler.deleteJob(getJobKey(jobName, jobGroup));
            }

            // 判断任务是否过期
            if (StringUtils.isNotNull(CronUtils.getNextExecution(job.getCronExpression()))) {
                // 执行调度任务
                scheduler.scheduleJob(jobDetail, trigger);
            }

            // 暂停任务
            if (QuartzConstant.Status.PAUSE.getValue().equals(job.getStatus())) {
                scheduler.pauseJob(getJobKey(jobName, jobGroup));
            }
        } catch (Exception e) {
            log.error("QuartzUtils 创建定时任务失败 {}", e.getMessage(), e);
        }
    }

    /**
     * 暂停定时任务
     *
     * @param scheduler 调度者
     * @param jobName   任务名称
     */
    public static void pauseScheduleJob(Scheduler scheduler, String jobName) {
        pauseScheduleJob(scheduler, jobName, null);
    }

    /**
     * 暂停定时任务
     *
     * @param scheduler 调度者
     * @param jobName   任务名称
     * @param jobGroup  任务组名
     */
    public static void pauseScheduleJob(Scheduler scheduler, String jobName, String jobGroup) {
        try {
            scheduler.pauseJob(getJobKey(jobName, jobGroup));
        } catch (Exception e) {
            log.error("QuartzUtils 暂停定时任务失败 {}", e.getMessage(), e);
        }
    }

    /**
     * 恢复定时任务
     *
     * @param scheduler 调度者
     * @param jobName   任务名称
     */
    public static void resumeScheduleJob(Scheduler scheduler, String jobName) {
        resumeScheduleJob(scheduler, jobName, null);
    }

    /**
     * 恢复定时任务
     *
     * @param scheduler 调度者
     * @param jobName   任务名称
     * @param jobGroup  任务组名
     */
    public static void resumeScheduleJob(Scheduler scheduler, String jobName, String jobGroup) {
        try {
            scheduler.resumeJob(getJobKey(jobName, jobGroup));
        } catch (Exception e) {
            log.error("QuartzUtils 恢复定时任务失败 {}", e.getMessage(), e);
        }
    }

    /**
     * 立即运行一次定时任务
     *
     * @param scheduler 调度者
     * @param jobName   任务名称
     */
    public static void triggerScheduleJob(Scheduler scheduler, String jobName) {
        triggerScheduleJob(scheduler, jobName, null);
    }

    /**
     * 立即运行一次定时任务
     *
     * @param scheduler 调度者
     * @param jobName   任务名称
     * @param jobGroup  任务组名
     */
    public static void triggerScheduleJob(Scheduler scheduler, String jobName, String jobGroup) {
        try {
            scheduler.triggerJob(getJobKey(jobName, jobGroup));
        } catch (Exception e) {
            log.error("QuartzUtils 立即运行一次定时任务失败 {}", e.getMessage(), e);
        }
    }

    /**
     * 删除定时任务
     *
     * @param scheduler 调度者
     * @param jobName   任务名称
     */
    public static void deleteScheduleJob(Scheduler scheduler, String jobName) {
        deleteScheduleJob(scheduler, jobName, null);
    }

    /**
     * 删除定时任务
     *
     * @param scheduler 调度者
     * @param jobName   任务名称
     * @param jobGroup  任务组名
     */
    public static void deleteScheduleJob(Scheduler scheduler, String jobName, String jobGroup) {
        try {
            scheduler.deleteJob(getJobKey(jobName, jobGroup));
        } catch (Exception e) {
            log.error("QuartzUtils 删除定时任务失败 {}", e.getMessage(), e);
        }
    }

    /**
     * 设置定时任务策略
     */
    public static CronScheduleBuilder handleCronScheduleMisfirePolicy(QuartzJob job, CronScheduleBuilder cb) {
        return switch (job.getMisfirePolicy()) {
            case QuartzConstant.MISFIRE_DEFAULT -> cb;
            case QuartzConstant.MISFIRE_IGNORE_MISFIRES -> cb.withMisfireHandlingInstructionIgnoreMisfires();
            case QuartzConstant.MISFIRE_FIRE_AND_PROCEED -> cb.withMisfireHandlingInstructionFireAndProceed();
            case QuartzConstant.MISFIRE_DO_NOTHING -> cb.withMisfireHandlingInstructionDoNothing();
            default -> throw new RuntimeException("The job misfire policy '" + job.getMisfirePolicy()
                + "' cannot be used in cron schedule tasks");
        };
    }

}
